home *** CD-ROM | disk | FTP | other *** search
/ Speccy ClassiX 1998 / Speccy ClassiX 98.iso / amiga_system / the_aminet / dev / gcc / ixemulsrc.lha / ixemul-41.4 / libsrc / crt0.c < prev    next >
C/C++ Source or Header  |  1995-09-27  |  11KB  |  389 lines

  1. /* revamped version by Loren J. Rittle. Thanks Loren !! */
  2.  
  3. /* I guess I should start to put my sources into RCS........ */
  4.  
  5. #include <exec/types.h>
  6. #include <exec/libraries.h>
  7. #include <exec/execbase.h>
  8.  
  9. /* have to use explicit 4 dereferencing here, since we can't always access
  10.    globals so early (a4 etc) */
  11. #define BASE_EXT_DECL
  12. #define BASE_EXT_DECL0
  13. #define BASE_NAME *(void **)4
  14. #include <inline/exec.h>
  15. #include <libraries/dosextens.h>
  16. #include <limits.h>
  17. #include "kprintf.h"
  18.  
  19. #include <sys/syscall.h>
  20. #ifdef BASECRT0
  21. #include <sys/exec.h>
  22. #endif /* BASECRT0 */
  23.  
  24. /* get the current revision number. Version control is automatically done by
  25.  * OpenLibrary(), I just have to check the revision number 
  26.  */
  27. #undef IX_VERSION
  28. #include "version.h"
  29.  
  30. #ifdef DEBUG_VERSION
  31. /* #undef IX_NAME */
  32. /* #define IX_NAME "ixkprinf.library" */
  33. #endif
  34.  
  35. #if defined(DEBUG_VERSION) && 0      /* Note:  This doesn't seem to work...  -fnf */
  36. static int inline __geta4() {int res;asm ("movel a4,%0" : "=g" (res));return res;}
  37. #endif
  38.  
  39. #define MSTRING(x) STRING(x)
  40. #define STRING(x) #x
  41.  
  42. struct Library *ixemulbase;
  43.  
  44. static int start_stdio(int, char **, char **);
  45.  
  46. /*
  47.  * Have to take care.. I may not use any library functions in this file,
  48.  * since they are exactly then used, when the library itself couldn't be
  49.  * opened...
  50.  */
  51.  
  52. extern int main();
  53. extern int expand_cmd_line;
  54. extern char *default_wb_window;
  55. extern int errno;
  56. extern char **environ;
  57. extern char *_ctype_;
  58. extern int sys_nerr;
  59. extern unsigned long __SaveSP;
  60. extern struct ExecBase *SysBase;
  61. extern struct Library *DOSBase;
  62. extern struct __sFILE **__sF;
  63. static int ENTRY();
  64. static int exec_entry();
  65.  
  66. /*
  67.  * This is the first code executed.  Note that a_magic has to be at
  68.  * a known offset from the start of the code section in order for
  69.  * execve() to know that the program that it is starting uses the
  70.  * ixemul library.
  71.  *
  72.  * The first instruction used to be a "jmp pc@(_ENTRY)", which when
  73.  * assembled by gas 2.5.2 produces an 8 byte 68020 PC relative jump
  74.  * rather than the desired 68000 short PC relative jump.  Changing
  75.  * it to "jmp pc@(_ENTRY:W)" generated the right instruction but
  76.  * a bad jmp offset.  So we use "jra _ENTRY" which seems to work
  77.  * fine on all m68k.  However, since programs are now in use
  78.  * linked with crt0 files with the 8 byte instruction, we need to
  79.  * maintain the hack in execve() that allows either jmp, and now
  80.  * the jra, and we need to ensure that a 16 bit displacement is
  81.  * required to reach ENTRY() or else we will have to add yet
  82.  * another pattern to match in execve().
  83.  *
  84.  */
  85.  
  86.  
  87. asm("
  88.     .text
  89.  
  90.     jra    _ENTRY        | by default jump to normal AmigaDOS startup
  91.     .align    2        | ensure exec starts at byte offset 4
  92.  
  93.     | this is a struct exec, for now only OMAGIC is supported
  94.     .globl    exec
  95. exec:
  96.     .word    ___machtype    | a_mid
  97.     .word    0407        | a_magic = OMAGIC
  98.     .long    ___text_size    | a_text
  99.     .long    ___data_size    | a_data
  100.     .long    ___bss_size    | a_bss
  101.     .long    0        | a_syms
  102.     .long    _exec_entry    | a_entry
  103.     .long    0        | a_trsize
  104.     .long    0        | a_drsize
  105.  
  106.     | word alignment is guaranteed
  107. ");
  108.  
  109. #ifdef BASECRT0
  110. extern int __datadata_relocs();
  111. extern int __data_size, __bss_size;
  112.  
  113. #ifdef RCRT0
  114. /* have to do this this way, or it is done base-relative.. */
  115. static inline int dbsize() 
  116. {
  117.   int res;
  118.   KPRINTF (("enter dbsize()\n"));
  119.   asm ("movel #___data_size,%0; addl #___bss_size,%0" : "=r" (res));
  120.   return res;
  121. }
  122.  
  123. static void inline
  124. ix_resident (void *base, int num, int a4, int size, void *relocs)
  125. {
  126.   typedef void (*func)(int, int, int, void *);
  127.  
  128.   KPRINTF (("enter ix_resident()\n"));
  129.   ((func)((int)base - 6*(SYS_ix_resident + 4))) (num, a4, size, relocs);
  130. }
  131.  
  132. #else
  133. static void inline
  134. ix_resident (void *base, int num, int a4)
  135. {
  136.   typedef void (*func)(int, int);
  137.  
  138.   KPRINTF (("enter ix_resident()\n"));
  139.   ((func)((int)base - 6*(SYS_ix_resident + 4))) (num, a4);
  140. }
  141. #endif
  142. #endif /* BASECRT0 */
  143.  
  144. static int
  145. exec_entry (struct Library *ixembase, int argc, char *argv[], char *env[])
  146. {
  147. #ifdef BASECRT0
  148.   register int a4;
  149.   /* needed, so that data can be accessed. ix_resident might change this
  150.      again afterwards */
  151.   asm volatile ("lea    ___a4_init,a4" : "=r" (a4) : "0" (a4));
  152.   asm volatile ("movel    a4,%0" : "=r" (a4) : "0" (a4));
  153.  
  154.   KPRINTF (("enter exec_entry()\n"));
  155. #ifdef RCRT0
  156.   ix_resident (ixembase, 4, a4, dbsize(), __datadata_relocs);
  157. #else
  158.   ix_resident (ixembase, 2, a4);
  159. #endif
  160. #endif /* BASECRT0 */
  161.   ixemulbase = ixembase;
  162.   return ix_exec_entry (argc, argv, env, &errno, start_stdio);
  163. }
  164.  
  165. /* this thing is best done with sprintf else, but it has to work without the
  166.  * library as well ;-(
  167.  */
  168. __inline static char *
  169. itoa (int num)
  170. {
  171.   short snum = num;
  172.  
  173.   /* how large can a long get...?? */
  174.   /* Answer (by ljr): best method to use (in terms of portability)
  175.      involves number theory.  The exact number of decimal digits
  176.      needed to store a given number of binary digits is
  177.  
  178.     ceiling ( number_of_binary_digits * log(2) / log(10) )
  179.      or
  180.     ceiling ( number_of_binary_digits * 0.301029996 )
  181.  
  182.      Since sizeof evaluates to the number of bytes a given type takes 
  183.      instead of the number of bits, we need to multiply sizeof (type) by
  184.      CHAR_BIT to obtain the number of bits.  Since an array size specifier
  185.      needs to be integer type, we multiply by 302 and divide by 1000 instead
  186.      of multiplying by 0.301029996.  Finally, we add 1 for the null terminator
  187.      and 1 because we want the ceiling of the function instead of the floor.
  188.      Funny thing about this whole affair is that you really wanted to know
  189.      the size a short could expand to be and not a long...  :-) I know
  190.      comments get out of date, etc.  The nice thing about this method is
  191.      that the size of the array is picked at compile time based upon the
  192.      number of bytes really needed by the local C implementation. */
  193.   static char buf[sizeof snum * CHAR_BIT * 302 / 1000 + 1 + 1];
  194.   char *cp;
  195.   
  196.   KPRINTF (("enter itoa()\n"));
  197.   buf[sizeof buf - 1] = 0;
  198.   cp = &buf[sizeof buf - 1];
  199.   do
  200.   {
  201.     *--cp = (snum % 10) + '0';
  202.     snum /= 10;
  203.   } while (snum);
  204.  
  205.   return cp;
  206. }
  207.  
  208. __inline static char *
  209. pstrcpy (char *start, char *arg)
  210. {
  211.   KPRINTF (("enter pstrcpy()\n"));
  212.   while (*start++=*arg++) ;
  213.   return start-1;
  214. }
  215.  
  216. __inline static char *
  217. build_warn (char *t1, int num1)
  218. {
  219.   static char buf[255];
  220.   char *cp;
  221.   
  222.   KPRINTF (("enter build_warn()\n"));
  223.   cp = pstrcpy (buf, t1);
  224.   cp = pstrcpy (cp, itoa (num1));
  225.  
  226.   return buf;
  227. }
  228.  
  229. /* Note: This routine must be far enough away from the start of code
  230.    so that the PC relative offset won't fit in a byte and the assembler
  231.    will generate the right instruction pattern that execve() is looking
  232.    for to know that this is a program that uses the ixemul.library. */
  233.  
  234. static int
  235. ENTRY (void)
  236. {
  237.   register unsigned char *rega0  asm("a0");
  238.   register unsigned long  regd0  asm("d0");
  239. #ifdef BASECRT0
  240.   register int a4;
  241. #endif /* BASECRT0 */
  242.  
  243.   UBYTE *aline = rega0;
  244.   ULONG alen = regd0;
  245.   int res;
  246.  
  247. #ifdef BASECRT0
  248.   struct Library *ibase;
  249.  
  250.   /* needed, so that data can be accessed. ix_resident() might change this
  251.      again afterwards */
  252.   asm volatile ("lea    ___a4_init,a4" : "=r" (a4) : "0" (a4));
  253.   asm volatile ("movel a4,%0" : "=r" (a4) : "0" (a4));
  254. #endif /* BASECRT0 */
  255.  
  256.   KPRINTF (("enter ENTRY()\n"));
  257.   KPRINTF (("alen = %ld; aline = '%s'\n", alen, aline));
  258. #ifndef BASECRT0
  259.   ixemulbase = OpenLibrary (IX_NAME, IX_VERSION);
  260.   if (ixemulbase)
  261. #else /* BASECRT0 */
  262.   KPRINTF (("ENTRY: a4 = $%lx\n", __geta4()));
  263.  
  264.   ibase = OpenLibrary (IX_NAME, IX_VERSION);
  265.   KPRINTF (("ibase = %lx\n", ibase));
  266.   if (ibase)
  267. #endif /* BASECRT0 */
  268.     {
  269.       /* just warn, in case the user tries to run program which might require
  270.        * more functions than are currently available under this revision. */
  271. #ifndef BASECRT0
  272.       if (ixemulbase->lib_Version == IX_VERSION &&
  273.       ixemulbase->lib_Revision < IX_REVISION)
  274. #else /* BASECRT0 */
  275.       if (ibase->lib_Version == IX_VERSION &&
  276.       ibase->lib_Revision < IX_REVISION)
  277. #endif /* BASECRT0 */
  278.     /* don't need to block signals, they are blocked until after 
  279.          * ix_startup() in current releases */
  280.     __request_msg (build_warn (IX_NAME " warning: needed revision "
  281.                      MSTRING (IX_REVISION) ", current revision ",
  282. #ifndef BASECRT0
  283.                             ixemulbase->lib_Revision), "Continue");
  284. #else /* BASECRT0 */
  285.                             ibase->lib_Revision), "Continue");
  286.  
  287. #ifdef RCRT0
  288.       ix_resident (ibase, 4, a4, dbsize(), __datadata_relocs);
  289. #else
  290.       ix_resident (ibase, 2, a4);
  291. #endif
  292.  
  293.       KPRINTF (("ix_resident: a4 = $%lx\n", __geta4()));
  294. #endif /* BASECRT0 */
  295.  
  296. #ifdef BASECRT0
  297.       ixemulbase = ibase;
  298.       asm volatile ("movel sp,a4@(___SaveSP:W)");
  299. #else
  300.       asm volatile ("movel sp,___SaveSP");
  301. #endif /* BASECRT0 */
  302.  
  303.       KPRINTF (("calling ix_startup()\n"));
  304.       res = ix_startup (aline, alen, 
  305.                 expand_cmd_line, default_wb_window, start_stdio, &errno);
  306.  
  307.       CloseLibrary (ixemulbase);
  308.  
  309.     }
  310.   else
  311.     {
  312.       struct Process *me = (struct Process *)((*(struct ExecBase **)4)->ThisTask);
  313.  
  314.       __request_msg ("Need at least version " MSTRING (IX_VERSION)
  315.              " of " IX_NAME ".", "Abort");
  316.       
  317.       /* quickly deal with the WB startup message, as the library couldn't do
  318.        * this for us. Nothing at all is done that isn't necessary to just shutup
  319.        * workbench..*/
  320.       if (! me->pr_CLI)
  321.         {
  322.       Forbid (); 
  323.       ReplyMsg ((WaitPort (& me->pr_MsgPort), GetMsg (& me->pr_MsgPort)));
  324.     }
  325.       
  326.     res = 20;
  327.     }
  328.   /* FIXME: It appears that libnix restores the value of the stack pointer
  329.      from ___SaveSP at a point equivalent to this in the libnix *crt0.S files.
  330.      Do we need to do that also?  -fnf */
  331.   return (res);
  332. }
  333.  
  334. int
  335. start_stdio (int argc, char **argv, char **env)
  336. {
  337.   int res;
  338.   extern void __init_stk (void);
  339. #ifndef BASECRT0
  340.   extern void etext ();
  341.   extern void _mcleanup ();
  342. #else /* BASECRT0 */
  343.  
  344.   KPRINTF (("start_stdio1: a4 = $%lx\n", __geta4()));
  345. #endif /* BASECRT0 */
  346.  
  347. #ifdef DEBUG_VERSION
  348.   KPRINTF (("enter start_stdio()\n"));
  349.   KPRINTF (("argc = %ld (args follow)\n", argc));
  350.   {
  351.     int i;
  352.     for (i = 0; i < argc; i++)
  353.       {
  354.     KPRINTF (("argv[%ld] = '%s'\n", i, argv[i]));
  355.       }
  356.   }
  357. #endif
  358.   
  359.   /* more to follow ;-) */
  360.   ix_get_vars2 (6, &_ctype_, &sys_nerr, &SysBase, &DOSBase, &__sF, &environ);
  361.   environ = env;
  362.  
  363.   /* Initialize the stack checking / stack growth code. */
  364.   __init_stk ();
  365.  
  366. #ifndef BASECRT0
  367. #ifdef MCRT0
  368.   atexit(_mcleanup);
  369.   monstartup(start_stdio, etext);
  370. #endif
  371. #endif /* not BASECRT0 */
  372.  
  373.   res = main (argc, argv, env);
  374.   return res;
  375. }
  376.  
  377. #ifndef BASECRT0
  378. #ifdef CRT0
  379. /*
  380.  * null mcount and moncontrol,
  381.  * just in case some routine is compiled for profiling
  382.  */
  383. asm(".globl mcount");
  384. asm(".globl _moncontrol");
  385. asm("_moncontrol:");
  386. asm("mcount: rts");
  387. #endif CRT0
  388. #endif /* not BASECRT0 */
  389.